#include "TestDocumentObjectListener.h"

#include "DocumentObjectMock.h"

#include<QtTest>

using namespace LDO;

TestDocumentObjectListener::TestDocumentObjectListener(QObject *parent)
    : QObject(parent)
    , IDocumentObjectListener()
{

}

void TestDocumentObjectListener::init()
{
    clear();
}

void TestDocumentObjectListener::cleanup()
{

}

void TestDocumentObjectListener::testInsertChildObject()
{
    auto parent = new DocumentObjectMock1();
    auto child1 = new DocumentObjectMock1();
    auto child2 = new DocumentObjectMock1();

    QCOMPARE(objectAboutToBeInsertedCallCount, 0);
    QCOMPARE(objectInsertedCallCount, 0);
    beginListeningToDocumentObject(parent);
    QCOMPARE(objectAboutToBeInsertedCallCount, 0);
    QCOMPARE(objectInsertedCallCount, 0);
    parent->addChildObject(child1);
    QCOMPARE(firstCalled, QString("documentObjectAboutToBeInserted"));
    QCOMPARE(objectAboutToBeInsertedCallCount, 1);
    QCOMPARE(objectAboutToBeInsertedParent, parent);
    QCOMPARE(objectAboutToBeInsertedChild, child1);
    QCOMPARE(objectAboutToBeInsertedIndex, 0);
    QCOMPARE(objectInsertedCallCount, 1);
    QCOMPARE(objectInsertedParent, parent);
    QCOMPARE(objectInsertedChild, child1);
    QCOMPARE(objectInsertedIndex, 0);
    clear();
    endListeningToDocumentObject(parent);
    QCOMPARE(objectAboutToBeInsertedCallCount, 0);
    QCOMPARE(objectInsertedCallCount, 0);
    clear();
    parent->addChildObject(child2);
    QCOMPARE(objectAboutToBeInsertedCallCount, 0);
    QCOMPARE(objectInsertedCallCount, 0);
}

void TestDocumentObjectListener::testRemoveChildObject()
{
    auto parent = new DocumentObjectMock1();
    auto child1 = new DocumentObjectMock1();
    auto child2 = new DocumentObjectMock1();
    parent->addChildObject(child1);
    parent->addChildObject(child2);

    QCOMPARE(objectAboutToBeRemovedCallCount, 0);
    QCOMPARE(objectRemovedCallCount, 0);
    beginListeningToDocumentObject(parent);
    QCOMPARE(objectAboutToBeRemovedCallCount, 0);
    QCOMPARE(objectRemovedCallCount, 0);
    parent->removeChildObject(child2);
    QCOMPARE(firstCalled, QString("documentObjectAboutToBeRemoved"));
    QCOMPARE(objectAboutToBeRemovedCallCount, 1);
    QCOMPARE(objectAboutToBeRemovedParent, parent);
    QCOMPARE(objectAboutToBeRemovedChild, child2);
    QCOMPARE(objectAboutToBeRemovedIndex, 1);
    QCOMPARE(objectRemovedCallCount, 1);
    QCOMPARE(objectRemovedParent, parent);
    QCOMPARE(objectRemovedChild, child2);
    QCOMPARE(objectRemovedIndex, 1);
    clear();
    parent->removeChildObject(child1);
    QCOMPARE(firstCalled, QString("documentObjectAboutToBeRemoved"));
    QCOMPARE(objectAboutToBeRemovedCallCount, 1);
    QCOMPARE(objectAboutToBeRemovedParent, parent);
    QCOMPARE(objectAboutToBeRemovedChild, child1);
    QCOMPARE(objectAboutToBeRemovedIndex, 0);
    QCOMPARE(objectRemovedCallCount, 1);
    QCOMPARE(objectRemovedParent, parent);
    QCOMPARE(objectRemovedChild, child1);
    QCOMPARE(objectRemovedIndex, 0);
    clear();
    endListeningToDocumentObject(parent);
    QCOMPARE(objectAboutToBeInsertedCallCount, 0);
    QCOMPARE(objectInsertedCallCount, 0);
    clear();
    parent->addChildObject(child2);
    QCOMPARE(objectAboutToBeInsertedCallCount, 0);
    QCOMPARE(objectInsertedCallCount, 0);
}

void TestDocumentObjectListener::testChangeStaticProperty()
{
    auto parent = new DocumentObjectMock1();

    QCOMPARE(objectPropertyAboutToChangeCallCount, 0);
    QCOMPARE(objectPropertyChangedCallCount, 0);
    beginListeningToDocumentObject(parent);
    QCOMPARE(objectPropertyAboutToChangeCallCount, 0);
    QCOMPARE(objectPropertyChangedCallCount, 0);

    parent->setString("toto");
    QCOMPARE(objectPropertyAboutToChangeCallCount, 1);
    QCOMPARE(objectPropertyAboutToChangeObject, parent);
    QCOMPARE(objectPropertyAboutToChangeProperty, QString("string"));
    QCOMPARE(objectPropertyAboutToChangeValue, QVariant(QString()));
    QCOMPARE(objectPropertyChangedCallCount, 1);
    QCOMPARE(objectPropertyChangedObject, parent);
    QCOMPARE(objectPropertyChangedProperty, QString("string"));
    QCOMPARE(objectPropertyChangedValue, QVariant(QString("toto")));
}

void TestDocumentObjectListener::testChangeDynamicProperty()
{

}


void TestDocumentObjectListener::testCannotListenTwice()
{
    auto parent = new DocumentObjectMock1();
    beginListeningToDocumentObject(parent);
    beginListeningToDocumentObject(parent);
    auto child = new DocumentObjectMock1();
    parent->addChildObject(child);
    QCOMPARE(objectAboutToBeInsertedCallCount, 1);
    QCOMPARE(objectInsertedCallCount, 1);
    parent->removeChildObject(child);
    QCOMPARE(objectAboutToBeRemovedCallCount, 1);
    QCOMPARE(objectRemovedCallCount, 1);
}

void TestDocumentObjectListener::testCannotInsertTwice()
{
    auto parent = new DocumentObjectMock1();
    auto child = new DocumentObjectMock1();
    beginListeningToDocumentObject(parent);
    parent->addChildObject(child);
    QCOMPARE(objectAboutToBeInsertedCallCount, 1);
    QCOMPARE(objectInsertedCallCount, 1);
    parent->addChildObject(child);
    QCOMPARE(objectAboutToBeInsertedCallCount, 1);
    QCOMPARE(objectInsertedCallCount, 1);
}

void TestDocumentObjectListener::testCannotRemoveTwice()
{
    auto parent = new DocumentObjectMock1();
    beginListeningToDocumentObject(parent);
    beginListeningToDocumentObject(parent);
    auto child = new DocumentObjectMock1();
    parent->addChildObject(child);
    QCOMPARE(objectAboutToBeInsertedCallCount, 1);
    QCOMPARE(objectInsertedCallCount, 1);
    parent->removeChildObject(child);
    QCOMPARE(objectAboutToBeRemovedCallCount, 1);
    QCOMPARE(objectRemovedCallCount, 1);
    parent->removeChildObject(child);
    QCOMPARE(objectAboutToBeRemovedCallCount, 1);
    QCOMPARE(objectRemovedCallCount, 1);
}

void TestDocumentObjectListener::clear()
{
    firstCalled = QString();
    objectAboutToBeInsertedCallCount = 0;
    objectAboutToBeInsertedParent = nullptr;
    objectAboutToBeInsertedChild = nullptr;
    objectAboutToBeInsertedIndex = -42;
    objectInsertedCallCount = 0;
    objectInsertedParent = nullptr;
    objectInsertedChild = nullptr;
    objectInsertedIndex = -42;

    objectAboutToBeRemovedCallCount = 0;
    objectAboutToBeRemovedParent = nullptr;
    objectAboutToBeRemovedChild = nullptr;
    objectAboutToBeRemovedIndex = -42;
    objectRemovedCallCount = 0;
    objectRemovedParent = nullptr;
    objectRemovedChild = nullptr;
    objectRemovedIndex = -42;

    objectPropertyAboutToChangeCallCount = 0;
    objectPropertyAboutToChangeObject = nullptr;
    objectPropertyAboutToChangeProperty = "__None__";
    objectPropertyAboutToChangeValue = QVariant();

    objectPropertyChangedCallCount = 0;
    objectPropertyChangedObject = nullptr;
    objectPropertyChangedProperty = "__None__";
    objectPropertyChangedValue = QVariant();
}


void TestDocumentObjectListener::documentObjectAboutToBeInserted(IDocumentObject *parent,
                                                                 IDocumentObject *child,
                                                                 int index)
{
    if (firstCalled.isEmpty())
        firstCalled = "documentObjectAboutToBeInserted";
    objectAboutToBeInsertedCallCount++;
    objectAboutToBeInsertedParent = parent;
    objectAboutToBeInsertedChild = child;
    objectAboutToBeInsertedIndex = index;
}

void TestDocumentObjectListener::documentObjectInserted(IDocumentObject *parent,
                                                        IDocumentObject *child,
                                                        int index)
{
    if (firstCalled.isEmpty())
        firstCalled = "documentObjectInserted";
    objectInsertedCallCount++;
    objectInsertedParent = parent;
    objectInsertedChild = child;
    objectInsertedIndex = index;
}

void TestDocumentObjectListener::documentObjectAboutToBeRemoved(IDocumentObject *parent,
                                                                IDocumentObject *child,
                                                                int index)
{
    if (firstCalled.isEmpty())
        firstCalled = "documentObjectAboutToBeRemoved";
    objectAboutToBeRemovedCallCount++;
    objectAboutToBeRemovedParent = parent;
    objectAboutToBeRemovedChild = child;
    objectAboutToBeRemovedIndex = index;
}

void TestDocumentObjectListener::documentObjectRemoved(IDocumentObject *parent,
                                                       IDocumentObject *child,
                                                       int index)
{
    if (firstCalled.isEmpty())
        firstCalled = "documentObjectRemoved";
    objectRemovedCallCount++;
    objectRemovedParent = parent;
    objectRemovedChild = child;
    objectRemovedIndex = index;
}

void TestDocumentObjectListener::documentObjectAboutToChangeProperty(const IDocumentObject *object,
                                                                     const QString &name,
                                                                     const QVariant &value)
{
    if (firstCalled.isEmpty())
        firstCalled = "documentObjectAboutToChangeProperty";

    objectPropertyAboutToChangeCallCount++;
    objectPropertyAboutToChangeObject = object;
    objectPropertyAboutToChangeProperty = name;
    objectPropertyAboutToChangeValue = value;
}

void TestDocumentObjectListener::documentObjectPropertyChanged(const IDocumentObject *object,
                                                               const QString &name,
                                                               const QVariant &value)
{
    if (firstCalled.isEmpty())
        firstCalled = "documentObjectPropertyChanged";

    objectPropertyChangedCallCount++;
    objectPropertyChangedObject = object;
    objectPropertyChangedProperty = name;
    objectPropertyChangedValue = value;
}
